#include "MemoryPool.hpp"
#include <cstring>

constexpr size_t POOL_SIZE = 10 * 1024 * 1024; // 10MB

MemoryPool::MemoryPool(size_t blockSize) :
    m_blockSize(std::max(blockSize, sizeof(BlockHeader))),
    m_totalBlocks(POOL_SIZE / m_blockSize),
    m_freeBlocks(m_totalBlocks),
    m_memory(new char[m_blockSize * m_totalBlocks]),
    m_freeList(nullptr)
{
    if (m_totalBlocks == 0) {
        delete[] m_memory;
        throw std::bad_alloc();
    }
    initializeFreeList();
}

MemoryPool::~MemoryPool() {
    delete[] m_memory;
    if (m_freeBlocks != m_totalBlocks) {
        std::cerr << "Memory leak detected! "
                  << (m_totalBlocks - m_freeBlocks) 
                  << " blocks not freed\n";
    }
}

void MemoryPool::initializeFreeList() {
    m_freeList = reinterpret_cast<BlockHeader*>(m_memory);
    
    BlockHeader* current = m_freeList;
    for (size_t i = 0; i < m_totalBlocks - 1; ++i) {
        current->next = reinterpret_cast<BlockHeader*>(
            reinterpret_cast<char*>(current) + m_blockSize);
        current = current->next;
    }
    current->next = nullptr;
}

void* MemoryPool::allocate() {
    if (!m_freeList) {
        throw std::bad_alloc();
    }
    
    BlockHeader* header = m_freeList;
    m_freeList = header->next;
    --m_freeBlocks;
    
    return static_cast<void*>(header);
}

void MemoryPool::deallocate(void* block) {
    if (!block) return;
    
    BlockHeader* header = static_cast<BlockHeader*>(block);
    header->next = m_freeList;
    m_freeList = header;
    ++m_freeBlocks;
}

void MemoryPool::printStatus() const {
    std::cout << "Memory Pool Status:\n"
              << "Block Size: " << m_blockSize << " bytes\n"
              << "Total Blocks: " << m_totalBlocks << "\n"
              << "Free Blocks: " << m_freeBlocks << "\n"
              << "Used Blocks: " << (m_totalBlocks - m_freeBlocks) << "\n";
}